package org.java.dao;

import java.beans.PropertyDescriptor;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.security.Timestamp;
import java.util.ArrayList;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.LineIterator;
import org.java.common.StringHelper;

public class FileDAO<T> {
	private final static String FILE_PATH = "/home/";
	ArrayList<T> records = new ArrayList<T>();
	File file = null;
	FileWriter fileWriter = null;
	BufferedWriter bufferedWriter = null;

	FileReader fileReader = null;
	BufferedReader bufferedReader = null;

	boolean isAutoClose = false;
	int index = 0;

	public FileDAO() {
		super();
	}

	private String getFileName(Class<?> clazz) {
		try {
			return clazz.getSimpleName();
		} catch (Exception e) {
			return "";
		}

	}

	private File getFile(Class<?> clazz) {
		try {
			if (file == null) {
				file = new File(FILE_PATH + getFileName(clazz));
				if (!file.exists()) {
					file.createNewFile();
				}
			}
			return file;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	private File getTempFile(Class<?> clazz) {
		try {
			File file2 = new File(FILE_PATH + getFileName(clazz) + "tmp");
			if (!file2.exists()) {
				file2.createNewFile();
			}

			return file2;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	private void getBufferedWriter(Class<?> clazz) {
		try {
			getFile(clazz);
			if (fileWriter == null) {
				fileWriter = new FileWriter(file, true);
			}
			if (bufferedWriter == null) {
				bufferedWriter = new BufferedWriter(fileWriter);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void getBufferedReader(Class<?> clazz) {
		try {
			getFile(clazz);
			if (fileReader == null) {
				fileReader = new FileReader(file);
			}
			if (bufferedReader == null) {
				bufferedReader = new BufferedReader(fileReader);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void autoClose() {
		this.isAutoClose = true;
	}

	public void close() {

		try {
			bufferedWriter.close();
		} catch (Exception e) {
		} finally {
			bufferedWriter = null;
		}
		try {
			fileWriter.close();
		} catch (Exception e) {
		} finally {
			fileWriter = null;
		}

		try {
			bufferedReader.close();
		} catch (Exception e2) {

		} finally {
			bufferedReader = null;
		}
		try {
			fileReader.close();
		} catch (Exception e2) {

		} finally {
			fileReader = null;
		}
		try {
			file = null;
		} catch (Exception e) {
		}
	}

	public void create(T obj) {
		try {
			Class<?> clazz = obj.getClass();
			Field[] fields = clazz.getDeclaredFields();
			StringBuilder data = new StringBuilder();
			for (Field field : fields) {
				try {
					PropertyDescriptor pd = new PropertyDescriptor(
							field.getName(), obj.getClass());
					String modifier = Modifier.toString(field.getModifiers());
					if (modifier.indexOf("static") < 0) {
						data.append(field.getName()).append("[")
								.append(pd.getReadMethod().invoke(obj))
								.append("] ");

					}
				} catch (Exception e) {
					// TODO: handle exception
				}
			}
			// FileUtils.writeStringToFile(getFile(obj), data.toString(), true);

			getBufferedWriter(obj.getClass());
			bufferedWriter.append(data.toString());
			bufferedWriter.newLine();

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (isAutoClose) {
				close();
			}
		}

	}

	public void update(T obj) {

	}

	public void del(T obj, String key, String value) {
		try {
			BufferedReader bufferedReader = new BufferedReader(new FileReader(
					getFile(obj.getClass())));

			BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(
					getTempFile(obj.getClass())));

			String data = null;
			try {
				String searchStr = String.format("%s[%s]", key, value);
				while ((data = bufferedReader.readLine()) != null) {
					if (data.indexOf(searchStr) < 0) {
						bufferedWriter.append(data);
						bufferedWriter.newLine();
					}
				}

				// FileUtils.copyFile(getTempFile(obj.getClass()),getFile(obj.getClass()));
			} finally {
				bufferedReader.close();
				bufferedWriter.close();
			}
		} catch (Exception e) {
			// TODO: handle exception
		}
	}

	public void find(Class<T> clazz, String key, String value) {
		LineIterator it = null;
		try {
			Field[] fields = clazz.getDeclaredFields();
			it = FileUtils.lineIterator(getFile(clazz));
			String searchStr = String.format("%s[%s]", key, value);
			records.clear();
			while (it.hasNext()) {
				String line = it.nextLine();
				if (line.indexOf(searchStr) >= 0) {
					T obj = clazz.newInstance();
					initObject(obj, fields, line);
					records.add(obj);
				}
			}
		} catch (Exception e) {
		} finally {
			try {
				LineIterator.closeQuietly(it);
			} catch (Exception e2) {
			}
		}
	}

	public void findAll(Class<T> clazz) {
		LineIterator it = null;
		try {
			Field[] fields = clazz.getDeclaredFields();
			it = FileUtils.lineIterator(getFile(clazz));
			records.clear();
			while (it.hasNext()) {
				String line = it.nextLine();
				T obj = clazz.newInstance();
				initObject(obj, fields, line);
				records.add(obj);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				LineIterator.closeQuietly(it);
			} catch (Exception e2) {
			}
		}
	}

	public void finds(Class<T> clazz, String key, ArrayList<String> snList) {

		try {
			Field[] fields = clazz.getDeclaredFields();
			getBufferedReader(clazz);
			String line = null;
			while ((line = bufferedReader.readLine()) != null) {
				for (String value : snList) {
					String searchStr = String.format("%s[%s]", key, value);
					if (line.indexOf(searchStr) >= 0) {
						T obj = clazz.newInstance();
						initObject(obj, fields, line);
						records.add(obj);
					}
				}
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (isAutoClose) {
				close();
			}
		}
	}

	public boolean next() {

		if (++index <= records.size()) {
			return true;
		} else {
			index = 0;
			return false;
		}
	}

	public T getRecord() {
		return records.get(index - 1);
	}

	private Object trim(Object clazzValue) {
		if (clazzValue == null) {
			return "";
		} else {
			return clazzValue;
		}
	}

	private void initObject(T t, Field[] fields, String line) {

		for (Field field : fields) {
			String modifier = Modifier.toString(field.getModifiers());
			if (modifier.indexOf("static") < 0) {
				try {

					String propertyName = field.getName();
					Object paramVal = null;
					Class<?> clazzField = field.getType();
					if (clazzField == String.class) {
						paramVal = StringHelper.getValue(line, propertyName);
					} else if (clazzField == short.class
							|| clazzField == Short.class) {
						paramVal = StringHelper.getValue(line, propertyName);
					} else if (clazzField == int.class
							|| clazzField == Integer.class) {
						paramVal = new Integer(StringHelper.getValue(line,
								propertyName));
					} else if (clazzField == long.class
							|| clazzField == Long.class) {
						paramVal = new Integer(StringHelper.getValue(line,
								propertyName));
					} else if (clazzField == float.class
							|| clazzField == Float.class) {
						paramVal = new Integer(StringHelper.getValue(line,
								propertyName));
					} else if (clazzField == double.class
							|| clazzField == Double.class) {
						paramVal = new Integer(StringHelper.getValue(line,
								propertyName));
					} else if (clazzField == boolean.class
							|| clazzField == Boolean.class) {
						paramVal = new Integer(StringHelper.getValue(line,
								propertyName));
					} else if (clazzField == byte.class
							|| clazzField == Byte.class) {
						paramVal = new Integer(StringHelper.getValue(line,
								propertyName));
					} else if (clazzField == char.class
							|| clazzField == Character.class) {
						paramVal = new Integer(StringHelper.getValue(line,
								propertyName));
					} else if (clazzField == Timestamp.class) {
						paramVal = new Integer(StringHelper.getValue(line,
								propertyName));
					}
					PropertyDescriptor pd = new PropertyDescriptor(
							propertyName, t.getClass());
					pd.getWriteMethod().invoke(t, paramVal);

				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}
}
